﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Reflection;
using Tree.Lifecycle;
using System.Configuration;
using ICSharpCode.SharpZipLib.Zip;
using ICSharpCode.SharpZipLib.Core;
using Tree;

namespace Grafeas.Log.Impl
{
    public class FileLogger : ILogAppender
    {
        private FileInfo file = null;

        private StreamWriter logFile = null;

        public FileLogger()
        {       
        }

        public void Write(string str)
        {
            Console.Out.WriteLine(str);
            logFile.WriteLine(str);
            logFile.Flush();
        }

        public string Name
        {
            get;
            set;
        }

        public string Pattern
        {
            get;
            set;
        }

        public string Path
        {
            get;
            set;
        }

        public string RotateTimePolice
        {
            get;
            set;
        }

        public string RotateSizePolice
        {
            get;
            set;
        }

        public void Setup()
        {
            if (string.IsNullOrEmpty(Path))
            {
                if (string.IsNullOrEmpty(this.Name))
                {
                    Name = Assembly.GetCallingAssembly().GetName().Name.ToLower();
                }

                Path = Environment.GetEnvironmentVariable("Appdata") + "\\" + this.Name + "\\";
                Path = Path + this.Name + "-" + Environment.UserName.Trim().ToLower() + ".log";
            }
            else
            {
                Path = Environment.ExpandEnvironmentVariables(Path);
            }

            file = new FileInfo(Path);

            if (!file.Directory.Exists)
            {
                file.Directory.Create();
            }

            if (file.Exists && NeedToRotate())
            {
                Rotate();
            }

            logFile = File.AppendText(Path);
            logFile.Flush();
        }

        public bool NeedToRotate()
        {
            return OlderThan() || BiggerThan();
        }

        public void Rotate()
        {
            bool reopen = false;

            if (logFile != null)
            {
                logFile.Flush();
                logFile.Close();
                logFile = null;
                reopen = true;
            }

            ZipLog();
            file.Delete();

            if (reopen)
            {
                logFile = File.AppendText(Path);
            }
        }

        private string ZipLog()
        {
            string filename = file.FullName;
            string zipFile = filename + "." + DateTime.Now.ToString("dd-MM-yyyy-HH-mm-ss") + ".zip";
            FileStream stream = File.Create(zipFile);
            ZipOutputStream zipStream = new ZipOutputStream(stream);
            zipStream.SetLevel(5);

            FileInfo fi = new FileInfo(filename);
            ZipEntry newEntry = new ZipEntry(fi.Name);
            newEntry.DateTime = fi.LastWriteTime;
            newEntry.Size = fi.Length;
            zipStream.PutNextEntry(newEntry);

            byte[] buffer = new byte[4096];

            using (FileStream streamReader = File.OpenRead(filename))
            {
                StreamUtils.Copy(streamReader, zipStream, buffer);
            }

            zipStream.CloseEntry();
            zipStream.IsStreamOwner = true;
            zipStream.Close();
            return zipFile;
        }

        private bool OlderThan()
        {
            TimeSpan span = Utils.PeriodFor(RotateTimePolice);
            DateTime last = file.LastWriteTime;
            if (span == TimeSpan.MinValue || last.Year <= 1601)
            {
                return false;
            }

            DateTime now = DateTime.Now;
            return now.Subtract(last) > span;
        }

        private bool BiggerThan()
        {
            if (!file.Exists)
            {
                return false;
            }
            long size = Utils.FileSizeFor(RotateSizePolice);
            if (size <= 0)
            {
                return false;
            }
            bool bigger = file.Length > size;
            return bigger;
        }
    }
}
